﻿#region Honorbuddy

#endregion

#region System

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows.Documents;
using System.Windows.Media;
using CommonBehaviors.Actions;
using Styx;
using Styx.Common;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Action = Styx.TreeSharp.Action;

namespace Simcraft
{
    public partial class SimcraftImpl
    {
        public static int ActiveEnemies
        {
            get { return UnfriendlyUnitsNearTarget(10f).Count(); }
        }

        public static Composite CallActionList(Composite list, CanRunDecoratorDelegate del)
        {
            return new Decorator(del, list);
        }


        public static Composite Cast(String spell, CanRunDecoratorDelegate del = null, WoWUnit target = null)
        {
            return new Decorator(del ?? (ret => true),
                new Action(delegate
                {
                    if (target == null || target == default(WoWUnit)) target = Me.CurrentTarget;
                    if (CastSpell(spell, TargetU, 3)) return RunStatus.Success;
                    return RunStatus.Failure;
                }));
        }



        public static Composite CastLoc(String spell, CanRunDecoratorDelegate del = null)
        {
            return new Decorator(del ?? (ret => true),
                new Action(delegate
                {

                    if (CastSpell(spell, TargetU, 3, StyxWoW.Me.CurrentTarget.Location))
                    {
                        _clickLocation = Me.CurrentTarget.Location;
                        _clickSpell = spell;
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;
                }));
        }


        public static Composite SelfCast(String spell, CanRunDecoratorDelegate del)
        {
            return new Decorator(del,
                new Action(delegate
                {
                    if (CastSpell(spell, StyxWoW.Me.ToUnit(), 3)) return RunStatus.Success;
                    return RunStatus.Failure;
                }));
        }

        public static bool DamageEnabled(bool refresh = false)
        {
            if (!refresh)
                _damageEnabled = Lua.GetReturnVal<Boolean>(
                    "return _G[\"kane_damage\"] == true", 0);
            return !_damageEnabled;
        }

        public static bool AoeEnabled(bool refresh = false)
        {
            if (!refresh)
                _aoeEnabled = Lua.GetReturnVal<Boolean>(
                    "return _G[\"kane_aoe\"] == true", 0);
            return !_aoeEnabled;
        }

        public static bool CooldownsEnabled(bool refresh = false)
        {
            if (!refresh)
                _aoeEnabled = Lua.GetReturnVal<Boolean>(
                    "return _G[\"kane_cds\"] == true", 0);
            return !_aoeEnabled;
        }

        #region [TargetU Checks]

        private static IEnumerable<WoWUnit> UnfriendlyUnitsTargetingMe
        {

            get
            {
                return ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(u => !u.IsDead
                                                                                        && u.CanSelect
                                                                                        && u.Attackable
                                                                                        && !u.IsFriendly
                                                                                        && u.Distance <= 10
                                                                                        && u.IsTargetingMeOrPet);
            }
        }

        private static IEnumerable<WoWUnit> UnfriendlyUnits
        {
            get
            {
                return ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(u => !u.IsDead
                                                                                        && u.CanSelect
                                                                                        && u.Attackable
                                                                                        && !u.IsFriendly
                                                                                        && u.Distance <= 10
                                                                                        &&
                                                                                        (u.Level > 25 ||
                                                                                         AttackingFriendlies(u)));
            }
        }

        public static int UnfriendlysMissingDebuff(String debuff, float dist)
        {
            return ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Count(u => !u.IsDead
                                                                                    && u.CanSelect
                                                                                    && u.Attackable
                                                                                    && !u.IsFriendly
                                                                                    && u.Distance <= dist
                                                                                    &&
                                                                                    GetAuraTimeLeft(u, debuff, true) ==
                                                                                    TimeSpan.Zero
                                                                                    &&
                                                                                    (u.Level > 25 ||
                                                                                     AttackingFriendlies(u)));
        }

        public static IEnumerable<WoWUnit> UnfriendlyUnitsNearTarget(float dist)
        {
            return ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(u =>
                !u.IsDead
                && u.CanSelect
                && u.Attackable
                && !u.IsFriendly
                && u.Distance <= dist);
        }

        public static bool AttackingFriendlies(WoWUnit u)
        {
            return u.IsTargetingMeOrPet
                   || u.IsTargetingMyPartyMember
                   || u.IsTargetingMyRaidMember
                   || u.IsTargetingAnyMinion;
        }

        public static bool ValidUnit(WoWUnit u)
        {
            if (u == null || !u.IsValid)
            {
                return false;
            }
            if (!u.CanSelect)
            {
                return false;
            }
            if (u.IsDead)
            {
                return false;
            }
            if (u.IsPlayer)
            {
                WoWPlayer up = u.ToPlayer();
                if (up.IsHorde == Me.IsHorde)
                {
                    return false;
                }
                if (up.IsAlliance == Me.IsAlliance)
                {
                    return false;
                }
                if (up.Guid == Me.CurrentTargetGuid && !CanAttackCurrentTarget)
                {
                    return false;
                }
                return true;
            }
            if (u.IsFriendly)
            {
                return false;
            }
            WoWPlayer uOwner = GetPlayerParent(u);
            if (uOwner != null && uOwner.IsAlive && !uOwner.IsMe)
            {
                if (!ValidUnit(uOwner))
                {
                    return false;
                }
                if (!Blacklist.Contains(uOwner, BlacklistFlags.Combat))
                {
                    return false;
                }
                if (!Me.IsPvPFlagged)
                {
                    return false;
                }
            }
            if (u.IsNonCombatPet)
            {
                return false;
            }
            if (IsIgnorableCritter(u))
            {
                return false;
            }
            return true;
        }

        public static bool CanAttackCurrentTarget
        {
            get
            {
                if (StyxWoW.Me.CurrentTarget == null)
                    return false;

                return Lua.GetReturnVal<bool>("return UnitCanAttack(\"player\",\"target\")", 0);
            }
        }

        public static bool IsIgnorableCritter(WoWUnit u)
        {
            if (!u.IsCritter)
                return false;

            // good enemy if BotPoi
            if (Styx.CommonBot.POI.BotPoi.Current.Guid == u.Guid &&
                Styx.CommonBot.POI.BotPoi.Current.Type == Styx.CommonBot.POI.PoiType.Kill)
                return false;

            // good enemy if Targeting
            if (Targeting.Instance.TargetList.Contains(u))
                return false;

            // good enemy if Threat towards us
            if (u.ThreatInfo.ThreatValue != 0 && u.IsTargetingMyRaidMember)
                return false;

            // Nah, just a harmless critter
            return true;
        }

        public static WoWPlayer GetPlayerParent(WoWUnit u)
        {
            // If it is a pet/minion/totem, lets find the root of ownership chain
            WoWUnit pOwner = u;
            while (true)
            {
                if (pOwner.OwnedByUnit != null)
                    pOwner = pOwner.OwnedByRoot;
                else if (pOwner.CreatedByUnit != null)
                    pOwner = pOwner.CreatedByUnit;
                else if (pOwner.SummonedByUnit != null)
                    pOwner = pOwner.SummonedByUnit;
                else
                    break;
            }

            if (u != pOwner && pOwner.IsPlayer)
                return pOwner as WoWPlayer;

            return null;
        }

        #endregion [TargetU Checks]

        #region Spell CD Helpers

        public static TimeSpan GetSpellCooldown(string spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                {
                    return results.Override.CooldownTimeLeft;
                }
                return results.Original.CooldownTimeLeft;
            }


            return TimeSpan.MaxValue;
        }

        public static WoWSpell GetSpell(int spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                    return results.Override;
                return results.Original;
            }


            return default(WoWSpell);
        }

        public static WoWSpell GetSpell(string spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                    return results.Override;
                return results.Original;
            }


            return default(WoWSpell);
        }

        public static bool GetSpellOnCooldown(String spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                {
                    return results.Override.Cooldown;
                }
                return results.Original.Cooldown;
            }

            return false;
        }

        public static bool GetSpellOnCooldownId(int spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                    return results.Override.Cooldown;
                return results.Original.Cooldown;
            }
            return false;
        }

        public static TimeSpan GetSpellCooldownId(int spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Original.CooldownTimeLeft;
            }
            return TimeSpan.MaxValue;
        }

        #endregion Spell CD

        #region BuffProxy Helpers


        public static int GetAuraStacks(WoWUnit unit, string auraName, bool fromMyAura = false)
        {
            if (unit != null)
            {
                WoWAura wantedAura =
                    unit.GetAllAuras()
                        .FirstOrDefault(
                            a => a.Name == auraName && a.Duration > 0 && (!fromMyAura || a.CreatorGuid == Me.Guid));
                return wantedAura != null ? (int) wantedAura.StackCount : 0;
            }
            return 0;
        }

        public static TimeSpan GetAuraTimeLeft(WoWUnit unit, string auraName, bool fromMyAura = false)
        {
            if (unit != null)
            {
                WoWAura wantedAura =
                    unit.GetAllAuras()
                        .FirstOrDefault(
                            a => a.Name == auraName && a.Duration > 0 && (!fromMyAura || a.CreatorGuid == Me.Guid));
                return wantedAura != null ? wantedAura.TimeLeft : TimeSpan.Zero;
            }
            return TimeSpan.Zero;
        }

        public static int GetAuraStacks(WoWUnit unit, int spellid, bool fromMyAura = false)
        {
            if (unit != null)
            {
                WoWAura wantedAura =
                    unit.GetAllAuras()
                        .FirstOrDefault(
                            a => a.SpellId == spellid && a.Duration > 0 && (!fromMyAura || a.CreatorGuid == Me.Guid));
                return wantedAura != null ? (int) wantedAura.StackCount : 0;
            }
            return 0;
        }

        public static TimeSpan GetAuraTimeLeft(WoWUnit unit, int spellid, bool fromMyAura = false)
        {
            if (unit != null)
            {
                WoWAura wantedAura =
                    unit.GetAllAuras()
                        .FirstOrDefault(
                            a => a.SpellId == spellid && a.Duration > 0 && (!fromMyAura || a.CreatorGuid == Me.Guid));
                return wantedAura != null ? wantedAura.TimeLeft : TimeSpan.Zero;
            }
            return TimeSpan.Zero;
        }


        #endregion

        #region [Spell / Logging]

        public static string LastCastSpell = "";
        public static WoWUnit LastCastUnit;
        public static DateTime LastCastTime = DateTime.Now;

        public static string NoGCDSpells =
            "[Heroic Strike] [Bloodbath] [Berserker Rage] [Shield Wall] [Last Stand] [Mocking Banner] [Demoralizing Shout] [Shield Block] [Shield Barrier] [Charge] [Enraged Regeneration] [Pummel] [Spell Reflection]";

        public static bool CastSpell(string spellName, WoWUnit u, int LC, WoWPoint loc = default(WoWPoint))
        {
            if (!ValidUnit(u) || u == null)
            {
                return false;
            }
            if (!SpellManager.GlobalCooldown || NoGCDSpells.Contains(spellName))
            {
                #region [Log Colors]

                Color Lc = Colors.Orange;
                switch (LC)
                {
                    case 0:
                        Lc = Colors.Green;
                        break;
                    case 1:
                        Lc = Colors.LightCoral;
                        break;
                    case 2:
                        Lc = Colors.Blue;
                        break;
                    case 3:
                        Lc = Colors.Yellow;
                        break;
                    case 4:
                        Lc = Colors.Red;
                        break;
                }

                #endregion

                if (SpellManager.CanCast(spellName, u))
                {
                    if (SpellManager.Cast(spellName, u))
                    {
                        Logging.Write("{0} on {1}", spellName, u.Name);
                        return true;
                    }
                    else
                    {
                        return false;
                    }

                    //Logging.Write("{0} - {1} - {2}",!Buff["Shield Charge"].Up,Cooldown["Shield Slam"].Remains < 0.1,Spell["Shield Charge"].Charges == 2);
                    //Logging.Write(Lc, "{0} -  {2} : {1} ", DateTime.Now.ToString("mm:ss:fff"), Energy.Regen, spellName);
                }
                return false;
            }
            else
            {
                return false;
            }
        }

        #endregion [Spell / Logging]
    }
}
#endregion